#region File Description
//-----------------------------------------------------------------------------
// MainForm.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
using System.Linq;
using System.Xml.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Diagnostics;

using OpenTK;

#endregion

namespace NLE
{




    /// <summary>
    /// Custom form provides the main user interface for the program.
    /// In this sample we used the designer to fill the entire form with a
    /// ModelViewerControl, except for the menu bar which provides the
    /// "File / Open..." option.
    /// </summary>
    public partial class MainForm : Form
    {

        ImageList _imageList = new ImageList();

        public string[] RegisteredNames = { "Name", "X", "Y", "Rotation", "ScaleX", "ScaleY", "zOrder", "Class", "Layer", "IsHidden", "TextureName", "OriginX", "OriginY" };

        public string GamePath { get; set; }
        public string GameArgs { get; set; }

        public string SavePath { get; set; }

        Process _game = new Process();

        public Process Game { get { return _game; } }

        public MainForm()
        {
            // Initialise designer view
            InitializeComponent();


            ImageControl.MainForm = this;


            // Events


            // Grid Size
            cmbGridSize.TextChanged += UpdateGrid;
            cmbGridSize.SelectedIndex = 4;

            // Level Mode
            cmbMode.SelectedIndexChanged += UpdateMode;
            cmbMode.SelectedIndex = 0;

            // Class selection
            cmbClass.KeyPress += new KeyPressEventHandler(cmbClass_KeyPress);

            // Image list used for image library
            _imageList.ImageSize = new System.Drawing.Size(24, 24);
            // Used for folders
            _imageList.Images.Add("Group", Properties.Resources.Folder);

            // Image library
            treeImages.ImageList = _imageList;
            treeImages.AfterSelect += new TreeViewEventHandler(LoadPreviewTexture);

            // Layers
            treeLayers.AfterSelect += new TreeViewEventHandler(treeLayers_AfterSelect);
            treeLayers.AfterLabelEdit += new NodeLabelEditEventHandler(treeLayers_AfterLabelEdit);
            treeLayers.CheckBoxes = true;
            treeLayers.AfterCheck += new TreeViewEventHandler(treeLayers_AfterCheck);
            // Although names aren't updated, just use the label to save data
            // They will then be loaded from file as names: user doesn't notice
            //treeLayers.LabelEdit = true;

            // Object properties
            dgProperties.KeyPress += new KeyPressEventHandler(dgProperties_KeyPress);
            dgProperties.CellValueChanged += new DataGridViewCellEventHandler(dgProperties_CellValueChanged);

            // Clear level button
            tlClearLevel.Click += new EventHandler(tlClearLevel_Click);

            // Add zoom selections
            for (int i = 1; i <= 100; i++)
            {
                cmbZoom.Items.Add(i * 10 + " %");
            }
            cmbZoom.SelectedIndex = 9;
            cmbZoom.SelectedIndexChanged += new EventHandler(cmbZoom_SelectedIndexChanged);

            cmbzOrder.SelectedIndex = 4;
        }

        void cmbZoom_SelectedIndexChanged(object sender, EventArgs e)
        {
            // Update camera zoom
            Camera.Instance.Zoom = float.Parse(cmbZoom.SelectedItem.ToString().Split(' ')[0]) / 100.0f;
        }

        void treeLayers_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
        {
            // Find a layer
            Layer result = ImageControl.Layers.Find(
                delegate(Layer l)
                {
                    return l.Name == e.Node.Name;
                }
            );

            if (result == null)
            {
                // Not found, maybe we tried editing an object, so lets look for all objects

                // Let's make an array
                List<LevelObject> tempList = new List<LevelObject>();
                foreach (var layer in ImageControl.Layers)
                {
                    if (layer.IsHidden) continue;

                    tempList.AddRange(layer.LevelObjects);
                }

                LevelObject resulto = tempList.Find(
                    delegate(LevelObject l)
                    {
                        return l.Name == e.Node.Name;
                    }
                );

                resulto.Name = e.Label;
            }
            else
            {
                result.Name = e.Label;
            }

            e.Node.Name = e.Label;
        }

        void treeLayers_AfterSelect(object sender, TreeViewEventArgs e)
        {

            var query = (from n in ImageControl.Layers
                         where n.Name == e.Node.Name
                         select n);


            if (query.ToList().Count() > 0)
            {
                ImageControl.ActiveLayer = query.Take(1).ElementAt(0);
            }
        }

        void treeLayers_AfterCheck(object sender, TreeViewEventArgs e)
        {

            if (e.Action == TreeViewAction.Unknown) return;

            var parentNode = e.Node.Parent;



            // Find a suitable layer


            // Did we check a layer or an object?
            if (parentNode == null)
            {
                // It's a parent node, so check all it's children

                // We checked a layer
                Layer result = ImageControl.Layers.Find(
                    delegate(Layer l)
                    {
                        return l.Name == e.Node.Name;
                    }
                );

                // Let's (un)check the layer
                result.IsHidden = !e.Node.Checked;

            }
            else
            {

                Layer result = ImageControl.Layers.Find(
                    delegate(Layer l)
                    {
                        return l.Name == parentNode.Name;
                    }
                );

                // We checked an object
                foreach (var item in result.LevelObjects)
                {
                    // Does this object have the same name as the checked node
                    if (item.Name == e.Node.Name)
                    {
                        item.IsHidden = !e.Node.Checked;
                    }
                }
            }
        }


        void dgProperties_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            ImageControl.UpdateProperties(dgProperties.Rows[e.RowIndex].Cells[0].Value as string);
        }

        void dgProperties_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
        {
            // Update the values of the current object properties

            if (e.KeyChar == (char)Keys.Return)
            {
                //ImageControl.UpdateProperties();
            }
        }

        void cmbClass_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)Keys.Return && !cmbClass.Items.Contains(cmbClass.Text))
            {
                cmbClass.Items.Add(cmbClass.Text);
            }
        }



        public void LoadPreviewTexture(object sender, TreeViewEventArgs e)
        {
            if (ImageControl.TextureLibrary.ContainsKey(treeImages.SelectedNode.Name))
            {
                ImageControl.PreviewImage = ImageControl.TextureLibrary[treeImages.SelectedNode.Name].Texture;
            }

        }

        public Texture2D LoadTexture(String Image)
        {

            String tempName = Path.GetFileNameWithoutExtension(Image);

            Texture2D tempTex = null;

            if (!File.Exists(Image))
            {
                MessageBox.Show("File not found: " + Image);
            }
            else
            {
                tempTex = new Texture2D();
                tempTex.Load(new Bitmap(Image));
            }

            // todo, check for errors

            return tempTex;
        }


        void UpdateMode(object sender, EventArgs e)
        {
            switch (cmbMode.SelectedIndex)
            {
                case 0:
                    ImageControl._currentMode = ImageControl.CurrentMode.PlacementMode;
                    break;
                case 1:
                    ImageControl._currentMode = ImageControl.CurrentMode.TranslationMode;
                    break;
                case 2:
                    ImageControl._currentMode = ImageControl.CurrentMode.RotationMode;
                    break;
                case 3:
                    ImageControl._currentMode = ImageControl.CurrentMode.ScaleMode;
                    break;
                case 4:
                    ImageControl._currentMode = ImageControl.CurrentMode.zOrderMode;
                    break;
                default:
                    break;
            }
            

        }

        

        void UpdateGrid(object sender, EventArgs e)
        {

            if (cmbGridSize.SelectedIndex == 0)
            {
                ImageControl.EnableGrid = false;
            }
            else if (cmbGridSize.SelectedIndex == -1)
            {
                float newGridSize = 0.0f;
                if (float.TryParse(cmbGridSize.Text, out newGridSize))
                {
                    if (newGridSize > 1.0f)
                    {
                        ImageControl.EnableGrid = true;
                        ImageControl.GridSize = newGridSize;
                    }
                    else
                    {
                        MessageBox.Show("Grid size must be larger than 2.");
                    }
                }
                else
                {
                    MessageBox.Show("Invalid grid size!");
                }
            }
            else
            {
                ImageControl.EnableGrid = true;
                ImageControl.GridSize = float.Parse(cmbGridSize.Items[cmbGridSize.SelectedIndex].ToString(), CultureInfo.InvariantCulture.NumberFormat);
            }
        }

        


        private void tlOptions_Click(object sender, EventArgs e)
        {
            using (Options settings = new Options())
            {
                settings.mainForm = this;
                settings.InitPath();
                settings.ShowDialog();



                // read properties from form once it's closed
            }

        }

        private void tlAddImage_Click(object sender, EventArgs e)
        {
            using (ImageAdd imageAdd = new ImageAdd())
            {
                imageAdd.mainForm = this;
                imageAdd.UpdateGroups();
                imageAdd.ShowDialog();

                // read properties from form once it's closed
            }
        }

        private void tlToggleProperties_Click(object sender, EventArgs e)
        {
            dgProperties.Visible = !dgProperties.Visible;
        }

        private void tlToggleContentBrowser_Click(object sender, EventArgs e)
        {
            treeImages.Visible = !treeImages.Visible;
        }

        private void tlAddImageMultiple_Click(object sender, EventArgs e)
        {
            using (ImageAddMultiple imageAdd = new ImageAddMultiple())
            {
                imageAdd.mainForm = this;
                imageAdd.UpdateGroups();
                imageAdd.ShowDialog();

                // read properties from form once it's closed
            }
        }
        private void tlDeleteImage_Click(object sender, EventArgs e)
        {
            if (treeImages.SelectedNode == null)
            {
                MessageBox.Show("Nothing to delete!");
                return;
            }
            if (MessageBox.Show("Are you sure you wish to delete image \"" + treeImages.SelectedNode.Name + "\" ? Deletion will remove this image from your library, as well as any objects that use it in the level!", "Delete image from library", MessageBoxButtons.YesNo) == DialogResult.Yes)
            {

                ImageControl.PreviewImage = null;


                // todo: go through all layers and delete every object which uses the image to be deleted

                //ImageControl.LevelObjects = (from o in ImageControl.LevelObjects
                //                             where o.Name != treeImages.SelectedNode.Name
                //                             select o).ToList<LevelObject>();
                foreach (var layer in ImageControl.Layers)
                {
                   var removeList = (from o in layer.LevelObjects
                                             where o.TextureName == treeImages.SelectedNode.Name
                                             select o).ToList<LevelObject>();

                   foreach (var item in removeList)
                   {
                       ImageControl.DeleteObject(item);
                   }
                }

                ImageControl.TextureLibrary.Remove(treeImages.SelectedNode.Name);

                _imageList.Images.RemoveByKey(treeImages.SelectedNode.Name);

                treeImages.Nodes.Remove(treeImages.SelectedNode);
            }
        }


        public void AddImageToLibrary(string Name, string Path, string Group)
        {
            if (ImageControl.TextureLibrary.ContainsKey(Name)) return; 

            Texture2D tryLoad = LoadTexture(Path);

            if (tryLoad == null)
            {
                MessageBox.Show("An error occured trying to load image:\n\n"+ Path + "\n\nPlease make sure the image dimensions are a multiple of 4 !");
                return;
            }

            ImageControl.TextureLibrary.Add(Name, new LibraryImage() { Texture = tryLoad, Path = Path, Name = Name, Group = Group });

            _imageList.Images.Add(Name, Image.FromFile(Path));
        }

        public void UpdateTreeView()
        {
            // Based on the current library, update the tree view
            ClearTree();

            foreach (var levelObject in ImageControl.TextureLibrary)
            {
                String Group = levelObject.Value.Group;
                String Name = levelObject.Value.Name;
                String Path = levelObject.Value.Path;

               if (String.IsNullOrEmpty(levelObject.Value.Group))
                {
                    treeImages.Nodes.Add(new TreeNode() { Name = Name, Text = Name });

                    treeImages.Nodes[Name].ImageKey = Name;
                    treeImages.Nodes[Name].SelectedImageKey = Name;
                }
                else
                {
                    // Does the group exist?

                    if (treeImages.Nodes[Group] == null)
                    {
                        // It doesn't, make a new one
                        treeImages.Nodes.Add(new TreeNode() { Name = Group, Text = Group + " (Group)" });

                        treeImages.Nodes[Group].ImageKey = "Group";
                        treeImages.Nodes[Group].SelectedImageKey = "Group";
                    }

                    treeImages.Nodes[Group].Nodes.Add(new TreeNode() { Name = Name, Text = Name });

                    treeImages.Nodes[Group].Nodes[Name].ImageKey = Name;
                    treeImages.Nodes[Group].Nodes[Name].SelectedImageKey = Name;
                }
            }

        }

        public void ResetLayers()
        {
            treeLayers.Nodes.Clear();

            ImageControl.Layers.Clear();

            ImageControl.ActiveLayer = ImageControl.AddLayer("Background");
        }

        public void ClearLevel()
        {
            foreach (var layer in ImageControl.Layers)
            {
                layer.LevelObjects.Clear();
            }
            //ImageControl.LevelObjects.Clear();
        }

        public void ClearTree()
        {
            treeImages.Nodes.Clear();
            //ResetLayers();
        }

        public void ClearUndoList()
        {
            ImageControl.UndoHandler.UndoList.Clear();
        }

        void tlClearLevel_Click(object sender, EventArgs e)
        {
            ClearLevel();
            ClearUndoList();
        }

        public void ClearLibrary()
        {
            // Tree is dependant on library

            ImageControl.TextureLibrary.Clear();
            ImageControl.PreviewImage = null;
        }

        void SaveLevelToFile(string filename)
        {

            var xmlDocument = new XDocument();

            var pImageControl = new XElement("ImageControl");
            xmlDocument.Add(pImageControl);

            var pLibrary = new XElement("Library");
            pImageControl.Add(pLibrary);

            // Save the used image library
            // AND GROUPS!!!!
            // TODO: don't do this for a exported level
            foreach (TreeNode item in treeImages.Nodes)
            {


                if (!ImageControl.TextureLibrary.ContainsKey(item.Name))
                {

                    var pGroup = new XElement(item.Name);
                    pLibrary.Add(pGroup);

                    foreach (TreeNode subitem in item.Nodes)
                    {

                        var pSubImages = new XElement("Image");
                        pGroup.Add(pSubImages);

                        var pName = new XElement("Name");
                        pName.Value = subitem.Name;
                        pSubImages.Add(pName);

                        var pPath = new XElement("Path");
                        pPath.Value = ImageControl.TextureLibrary[subitem.Name].Path;
                        pSubImages.Add(pPath);

                    }
                }
                else
                {

                    var pImages = new XElement("Image");
                    pLibrary.Add(pImages);

                    var pName = new XElement("Name");
                    pName.Value = item.Name;
                    pImages.Add(pName);

                    var pPath = new XElement("Path");
                    pPath.Value = ImageControl.TextureLibrary[item.Name].Path;
                    pImages.Add(pPath);
                }
            }


            var pLevel = new XElement("Level");
            pImageControl.Add(pLevel);

            var pProperties = new XElement("Properties");
            pLevel.Add(pProperties);

            foreach (var kvp in ImageControl.Properties)
            {
                var pCustom = new XElement(kvp.Key);
                pCustom.Value = kvp.Value;
                pProperties.Add(pCustom);
            }

            if (!String.IsNullOrEmpty(GamePath))
            {
                var pGamePath = new XElement("GamePath");
                pGamePath.Value = GamePath;
                pProperties.Add(pGamePath);
            }

            if (!String.IsNullOrEmpty(GameArgs))
            {
                var pGameArgs = new XElement("GameArgs");
                pGameArgs.Value = GameArgs;
                pProperties.Add(pGameArgs);
            }


            foreach (var layer in ImageControl.Layers)
            {


                foreach (var levelobject in layer.LevelObjects)
                {

                    var pObjects = new XElement("Object");
                    pLevel.Add(pObjects);

                    var pTextureName = new XElement("TextureName");
                    pTextureName.Value = levelobject.TextureName;
                    pObjects.Add(pTextureName);

                    var pName = new XElement("Name");
                    pName.Value = levelobject.Name;
                    pObjects.Add(pName);

                    var pX = new XElement("X");
                    pX.Value = levelobject.Position.X.ToString(NumberFormatInfo.InvariantInfo);
                    pObjects.Add(pX);

                    var pY = new XElement("Y");
                    pY.Value = levelobject.Position.Y.ToString(NumberFormatInfo.InvariantInfo);
                    pObjects.Add(pY);



                    var pRotation = new XElement("Rotation");
                    pRotation.Value = levelobject.Rotation.ToString(NumberFormatInfo.InvariantInfo);
                    pObjects.Add(pRotation);

                    var pScaleX = new XElement("ScaleX");
                    pScaleX.Value = levelobject.Scale.X.ToString(NumberFormatInfo.InvariantInfo);
                    pObjects.Add(pScaleX);

                    var pScaleY = new XElement("ScaleY");
                    pScaleY.Value = levelobject.Scale.Y.ToString(NumberFormatInfo.InvariantInfo);
                    pObjects.Add(pScaleY);

                    var pzOrder = new XElement("zOrder");
                    pzOrder.Value = levelobject.zOrder.ToString(NumberFormatInfo.InvariantInfo);
                    pObjects.Add(pzOrder);

                    var pIsHidden = new XElement("IsHidden");
                    pIsHidden.Value = levelobject.IsHidden.ToString(NumberFormatInfo.InvariantInfo);
                    pObjects.Add(pIsHidden);

                    var pClass = new XElement("Class");
                    pClass.Value = levelobject.Class == null ? String.Empty : levelobject.Class;
                    pObjects.Add(pClass);

                    var pOriginX = new XElement("OriginX");
                    pOriginX.Value = levelobject.Origin.X.ToString(NumberFormatInfo.InvariantInfo);
                    pObjects.Add(pOriginX);

                    var pOriginY = new XElement("OriginY");
                    pOriginY.Value = levelobject.Origin.Y.ToString(NumberFormatInfo.InvariantInfo);
                    pObjects.Add(pOriginY);

                    var pLayer = new XElement("Layer");
                    // Get value from the treeview to update user edited values
                    pLayer.Value = treeLayers.Nodes[layer.Name].Text == null ? String.Empty : treeLayers.Nodes[layer.Name].Text;
                    pObjects.Add(pLayer);

                    // Add custom properties
                    foreach (var kvp in levelobject.Properties)
                    {

                        // Don't allow the user to add reserved words
                        if (RegisteredNames.Contains(kvp.Key))
                        {
                            continue;
                            //...
                        }

                        var pCustom = new XElement(kvp.Key);
                        pCustom.Value = kvp.Value;
                        pObjects.Add(pCustom);
                    }
                }
            }

            xmlDocument.Save(filename);


        }

        private void tlSaveAs_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFileDialog1 = new SaveFileDialog();
            saveFileDialog1.Filter = "XML File|*.xml";
            saveFileDialog1.Title = "Save your level";
            saveFileDialog1.ShowDialog();

            // If the file name is not an empty string open it for saving.
            if (!String.IsNullOrEmpty(saveFileDialog1.FileName))
            {
                SaveLevelToFile(saveFileDialog1.FileName);
                SavePath = saveFileDialog1.FileName;
            }
            else
            {
                //MessageBox.Show("You did not select a valid location! Level was NOT saved!");
            }
        }

        private void tlSave_Click(object sender, EventArgs e)
        {
            if (String.IsNullOrEmpty(SavePath))
            {
                tlSaveAs_Click(sender, e);
            }
            else
            {
                SaveLevelToFile(SavePath);
            }
        }

        private void tlOpen_Click(object sender, EventArgs e)
        {
            OpenFileDialog fileDialog = new OpenFileDialog();

            //// Default to the directory which contains our content files.
            //string assemblyLocation = Assembly.GetExecutingAssembly().Location;
            //string relativePath = Path.Combine(assemblyLocation, "../../../../Content");
            //string contentPath = Path.GetFullPath(relativePath);

            //fileDialog.InitialDirectory = contentPath;

            fileDialog.Title = "Load a level";

            fileDialog.Filter = "XML Files (*.xml)|*.xml|" +
                                "All Files (*.*)|*.*";

            if (fileDialog.ShowDialog() == DialogResult.OK)
            {

                string tempLevelFilename = fileDialog.FileName;

                SavePath = tempLevelFilename;

                var xmlDoc = XDocument.Load(tempLevelFilename);


                //// First, clear and load the library, level and treeview
                ResetLayers();
                ClearLevel();
                ClearTree();
                ClearLibrary();



                IEnumerable<XElement> xmlObjects = xmlDoc.Root.Descendants("Library").Descendants();

                foreach (var item in xmlObjects)
                {
                    string itemname = item.Name.ToString();
                    if (itemname.Equals("Image") && item.Parent.Name.ToString().Equals("Library"))
                    {
                        String tempName = item.Element("Name").Value;
                        String tempFilename = item.Element("Path").Value;

                        AddImageToLibrary(tempName, tempFilename, String.Empty);
                    }
                    else
                    {
                        foreach (var subitem in item.Descendants("Image"))
                        {
                            string groupname = subitem.Parent.Name.ToString();

                            String tempName = subitem.Element("Name").Value;
                            String tempFilename = subitem.Element("Path").Value;

                            AddImageToLibrary(tempName, tempFilename, groupname);
                        }
                    }
                }

                UpdateTreeView();

                xmlObjects = xmlDoc.Root.Descendants("Object");

                // Load all the objects after we loaded the library
                //var query = (from p in xmlObjects
                //             select new LevelObject
                //             {
                //                 Name = p.Element("Name").Value,
                //                 Position = new Vector2(float.Parse(p.Element("X").Value, NumberFormatInfo.InvariantInfo), float.Parse(p.Element("Y").Value, NumberFormatInfo.InvariantInfo)),
                //                 Rotation = float.Parse(p.Element("Rotation").Value, NumberFormatInfo.InvariantInfo),
                //                 Scale = float.Parse(p.Element("Scale").Value, NumberFormatInfo.InvariantInfo),
                //                 zOrder = float.Parse(p.Element("zOrder").Value, NumberFormatInfo.InvariantInfo),
                //                 Class = p.Element("Class").Value,
                //             }
                //                 );
                List<LevelObject> query = new List<LevelObject>();
                foreach (XElement p in xmlObjects)
                {

                    // Find a suitable layer
                    Layer result = ImageControl.Layers.Find(
                        delegate(Layer l)
                        {
                            return l.Name == p.Element("Layer").Value;
                        }
                    );

                    // We didn't find the loaded layer yet, so let's add it
                    if (result == null)
                    {
                        result = ImageControl.AddLayer(p.Element("Layer").Value);
                    }

                    LevelObject tempObject = new LevelObject
                    {
                        TextureName = p.Element("TextureName").Value,
                        Name = p.Element("Name").Value,
                        Position = new Vector2(float.Parse(p.Element("X").Value, NumberFormatInfo.InvariantInfo), float.Parse(p.Element("Y").Value, NumberFormatInfo.InvariantInfo)),
                        Origin = new Vector2(float.Parse(p.Element("OriginX").Value, NumberFormatInfo.InvariantInfo), float.Parse(p.Element("OriginY").Value, NumberFormatInfo.InvariantInfo)),
                        Rotation = float.Parse(p.Element("Rotation").Value, NumberFormatInfo.InvariantInfo),
                        Scale = new Vector2(float.Parse(p.Element("ScaleX").Value, NumberFormatInfo.InvariantInfo), float.Parse(p.Element("ScaleY").Value, NumberFormatInfo.InvariantInfo)),
                        zOrder = float.Parse(p.Element("zOrder").Value, NumberFormatInfo.InvariantInfo),
                        Class = p.Element("Class").Value,
                        IsHidden = p.Element("IsHidden").Value.Equals("True") ? true : false,
                        Layer = result,
                    };

                    ImageControl.AddToLayer(result, tempObject);

                    foreach (XElement xmlProperty in p.Elements())
                    {
                        string propertyName = xmlProperty.Name.ToString();
                        string propertyValue = xmlProperty.Value.ToString();

                        // Don't allow the user to add reserved words
                        if (RegisteredNames.Contains(propertyName))
                        {
                            continue;
                            //...
                        }

                        tempObject.Properties[propertyName] = propertyValue;
                    }

                    query.Add(tempObject);

                }

                xmlObjects = xmlDoc.Root.Descendants("Properties");

                foreach (XElement xmlProperty in xmlObjects.Elements())
                {


                    string propertyName = xmlProperty.Name.ToString();
                    string propertyValue = xmlProperty.Value.ToString();

                    if (propertyName.Equals("GamePath"))
                    {
                        GamePath = propertyValue;
                    }
                    else if (propertyName.Equals("GameArgs"))
                    {
                        GameArgs = propertyValue;
                    }

                    ImageControl.Properties[propertyName] = propertyValue;
                }

                ImageControl.SetPropertiesForLevel();


                foreach (var p in query)
                {
                    if (!cmbClass.Items.Contains(p.Class))
                    {
                        cmbClass.Items.Add(p.Class);
                    }

                    //ImageControl.LevelObjects.Add(p);
                }
            }
        }

        private void tlNewDoc_Click(object sender, EventArgs e)
        {
            ResetLayers();
            ClearLevel();
            ClearTree();
            ClearLibrary();

            ImageControl.Properties.Clear();

            cmbClass.Items.Clear();

            //dgProperties.Rows.Clear();

            ClearUndoList();
            ClearRedoList();
        }

        private void tlUndo_Click(object sender, EventArgs e)
        {
            ImageControl.UndoHandler.DoUndo();
        }

        private void tlRedo_Click(object sender, EventArgs e)
        {
            ImageControl.UndoHandler.DoRedo();
        }

        public void AddUndoItem(Action a)
        {
            ImageControl.UndoHandler.UndoList.Push(a);

            ClearRedoList();
        }

        void ClearRedoList()
        {
            ImageControl.UndoHandler.RedoList.Clear();
        }

        public void btnTest_Click(object sender, EventArgs e)
        {
            if (String.IsNullOrEmpty(GamePath))
            {
                MessageBox.Show("Please configure your game first.");
                tlOptions_Click(sender, e);
            }
            else
            {
                tlSave_Click(sender, e);


                _game.StartInfo.FileName = GamePath;
                _game.StartInfo.Arguments = GameArgs;
                _game.StartInfo.WorkingDirectory = Path.GetDirectoryName(GamePath);

                _game.Start();

                tlStop.Enabled = true;

            }
        }



        void _game_Exited(object sender, EventArgs e)
        {
            tlStop.Enabled = false;
        }

        private void tlStop_Click(object sender, EventArgs e)
        {
            _game.Kill();
            tlStop.Enabled = false;
        }


        private void tlRemoveCustomProperty_Click(object sender, EventArgs e)
        {

        }

        private void splitContainer2_Panel2_Paint(object sender, PaintEventArgs e)
        {

        }

        private void tlAddLayer_Click(object sender, EventArgs e)
        {
            ImageControl.AddLayer("New Layer");
        }

        private void tlRemoveLayer_Click(object sender, EventArgs e)
        {
            // todo; ask if he wants to keep existing layer data
            if (treeLayers.SelectedNode == null)
            {
                MessageBox.Show("No layer selected!");
                return;
            }

            Layer result = ImageControl.Layers.Find(
                delegate(Layer l)
                {
                    return l.Name == treeLayers.SelectedNode.Name;
                }
            );
            // todo: delete all associated objects with the layer
            

            // Remove it
            ImageControl.Layers.Remove(result);

            if (result == ImageControl.ActiveLayer)
            {
                ImageControl.ActiveLayer = null;
            }

            // Also remove the node

            treeLayers.Nodes.Remove(treeLayers.SelectedNode);



        }

        private void tlMoveLayerUp_Click(object sender, EventArgs e)
        {
            TreeNode node = treeLayers.SelectedNode;
                
            treeLayers.SelectedNode.MoveUp();



            treeLayers.SelectedNode = node;
                    
        }

        private void tlMoveLayerDown_Click(object sender, EventArgs e)
        {
            TreeNode node = treeLayers.SelectedNode;

            treeLayers.SelectedNode.MoveDown();



            treeLayers.SelectedNode = node;
        }









        /// <summary>
        /// Event handler for the Open menu option.
        /// </summary>
        //void OpenMenuClicked(object sender, EventArgs e)
        //{
        //    OpenFileDialog fileDialog = new OpenFileDialog();

        //    // Default to the directory which contains our content files.
        //    string assemblyLocation = Assembly.GetExecutingAssembly().Location;
        //    string relativePath = Path.Combine(assemblyLocation, "../../../../Content");
        //    string contentPath = Path.GetFullPath(relativePath);

        //    fileDialog.InitialDirectory = contentPath;

        //    fileDialog.Title = "Load Model";

        //    fileDialog.Filter = "Model Files (*.fbx;*.x)|*.fbx;*.x|" +
        //                        "FBX Files (*.fbx)|*.fbx|" +
        //                        "X Files (*.x)|*.x|" +
        //                        "All Files (*.*)|*.*";

        //    if (fileDialog.ShowDialog() == DialogResult.OK)
        //    {
        //        LoadModel(fileDialog.FileName);
        //    }
        //}


        /// <summary>
        /// Loads a new 3D model file into the ModelViewerControl.
        /// </summary>
        //void LoadModel(string fileName)
        //{
        //    Cursor = Cursors.WaitCursor;

        //    // Unload any existing model.
        //    modelViewerControl.Model = null;
        //    contentManager.Unload();

        //    // Tell the ContentBuilder what to build.
        //    contentBuilder.Clear();
        //    contentBuilder.Add(fileName, "Model", null, "ModelProcessor");

        //    // Build this new model data.
        //    string buildError = contentBuilder.Build();

        //    if (string.IsNullOrEmpty(buildError))
        //    {
        //        // If the build succeeded, use the ContentManager to
        //        // load the temporary .xnb file that we just created.
        //        modelViewerControl.Model = contentManager.Load<Model>("Model");
        //    }
        //    else
        //    {
        //        // If the build failed, display an error message.
        //        MessageBox.Show(buildError, "Error");
        //    }

        //    Cursor = Cursors.Arrow;
        //}


    }
}
public static class Extensions
{
    public static void MoveUp(this TreeNode node)
    {
        TreeNode parent = node.Parent;
        TreeView view = node.TreeView;
        if (parent != null)
        {
            int index = parent.Nodes.IndexOf(node);
            if (index > 0)
            {
                parent.Nodes.RemoveAt(index);
                parent.Nodes.Insert(index - 1, node);
            }
        }
        else if (node.TreeView.Nodes.Contains(node)) //root node
        {
            int index = view.Nodes.IndexOf(node);
            if (index > 0)
            {
                view.Nodes.RemoveAt(index);
                view.Nodes.Insert(index - 1, node);
            }
        }
    }

    public static void MoveDown(this TreeNode node)
    {
        TreeNode parent = node.Parent;
        TreeView view = node.TreeView;
        if (parent != null)
        {
            int index = parent.Nodes.IndexOf(node);
            if (index < parent.Nodes.Count -1)
            {
                parent.Nodes.RemoveAt(index);
                parent.Nodes.Insert(index + 1, node);
            }
        }
        else if (view != null && view.Nodes.Contains(node)) //root node
        {
            int index = view.Nodes.IndexOf(node);
            if (index < view.Nodes.Count - 1)
            {
                view.Nodes.RemoveAt(index);
                view.Nodes.Insert(index + 1, node);
            }
        }
    }
}